package threadSafe;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.TimeUnit;

/**
 * @author： pang-yun
 * @date： 2021-10-18 14:56
 * 功能目的 ：用于 练习题  买票是否线程安全
 */

@Slf4j
public class ExerciseSell {
    public static void main(String[] args) {
        // 售票窗口
        TicketWindow ticketWindow = new TicketWindow(1000);

        // 线程集合
        List<Thread> threadList = new ArrayList<>();

        // 线程安全的集合来
        List<Integer> list = new Vector<>();
        // 模拟多人买票
        for (int i = 0; i < 6000; i++) {
            Thread thread = new Thread(() -> {
                int account = ticketWindow.sell(randomAccount());
                try {
                    TimeUnit.SECONDS.sleep(randomAccount());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.add(account);

            });

            //没有多个线程操作 不会出现问题
            threadList.add(thread);
            thread.start();
        }


        for (Thread thread : threadList
        ) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        //统计剩余票数 和 买出的票数
        // 注意 统计 使用的是主线程  必须等 所有的买票线程执行完毕 才能 统计 因此需要 循环遍历 thread.join
        log.info("余票 : {}", ticketWindow.getCount());
        log.info("买出的票数: {}", list.stream().mapToInt(i -> i).sum());

    }

    // random 为线程安全
    static Random random = new Random();

    //随机 1~5
    public static int randomAccount() {
        return random.nextInt(5) + 1;
    }
}

//售票窗口
class TicketWindow {
    private int count;

    public TicketWindow(int count) {
        this.count = count;
    }

    // 获取 余票数量
    public int getCount() {
        return count;
    }

    // 售票
    public synchronized int sell(int account) {
        if (this.count >= account) {
            this.count -= account;
            return account;
        }
        return 0;
    }
}
